Unit myGraphics;{$mode objfpc}{$H+}

Interface

Uses Classes, DateUtils, Dialogs, FileUtil, Forms, Sdl, Sdl_image,
    Sdl_ttf, SysUtils, Windows;

Function PixelColor(SrcSurface: Psdl_surface; X, Y: Integer): UINT32;
Procedure InitSinCos;
Procedure DrawPixel(DstSurface: Psdl_surface; X, Y: Integer;
    R, G, B, Alpha: Uint8);
Procedure DrawPixel(DstSurface: Psdl_surface; X, Y: Integer; R, G, B: Uint8);
Procedure DrawPixel(DstSurface: Psdl_surface; X, Y: Integer; Color: Uint32);
Procedure DrawPixel(DstSurface: Psdl_surface; X, Y: Integer;
    Color: Uint32; Alpha: Uint8);
Procedure TransparentColor(PaintBoard: PSDL_Surface; Color: TSDL_Color);
Procedure TransparentColor(PaintBoard: PSDL_Surface; Color: UINT32);
Procedure AlphaSourceSurface(PaintBoard: PSDL_Surface; Alpha: Uint8);
Procedure BlitSurface(SrcSurface: PSDL_Surface; SrcRect: PSDL_Rect;
    DesSurface: PSDL_Surface; DesRect: PSDL_Rect);
Procedure AlphaBlitSurface(SrcSurface: PSDL_Surface; SrcRect: PSDL_Rect;
    DesSurface: PSDL_Surface; DesRect: PSDL_Rect; Alpha: Uint8);
Function OpenTTFFont(Font_file: String; Font_size: Integer): PTTF_FONT;
Procedure CloseTTFFont(Var Font: PTTF_FONT);
Function CloseColor(Fg_color, Bg_color, Color: UINT32): Boolean;
Function CreateColorSurface(Width, Height: Integer;
    Color: TSDL_Color): PSDL_Surface;
Procedure FreeSurface(Var ImageSurface: PSDL_Surface);
Function LoadImage(ImageFile: String): PSDL_Surface;
Function LoadImageAlpha(ImageFile: String): PSDL_Surface;
Function BackupSurface(PaintBoard: PSDL_Surface;
    BackupRect: TSDL_Rect): PSDL_Surface;
Procedure RestoreSurface(PaintBoard: PSDL_Surface;
    BackupSurface: PSDL_Surface; BackupRect: TSDL_Rect);
Procedure RotateSurfaceRad(DstSurface, SrcSurface: PSDL_Surface;
    SrcRect: PSDL_Rect; DestX, DestY, OffsetX, OffsetY: Integer; Angle: Single);
Procedure RotateSurfaceDeg(DstSurface, SrcSurface: PSDL_Surface;
    SrcRect: PSDL_Rect; DestX, DestY, OffsetX, OffsetY: Integer; Angle: Integer);
Procedure DrawLine(DstSurface: PSDL_Surface; X1, Y1, X2, Y2: Integer;
    Color: Cardinal);
Procedure DrawLine(DstSurface: PSDL_Surface; X1, Y1, X2, Y2: Integer;
    Color: TSDL_Color);
Procedure AaDrawLine(Dst: PSDL_Surface; X1, Y1, X2, Y2: Integer;
    Color: Cardinal);
Procedure DrawThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; Color: Cardinal);
Procedure DrawThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; Color: TSDL_Color);
Procedure AaDrawThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; Color: Cardinal);
Procedure AaDrawThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; Color: TSDL_Color);
Procedure AaDrawShadowThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; FgColor, BgColor: Cardinal);
Procedure AaDrawShadowThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; FgColor, BgColor: TSDL_Color);
Procedure DrawShadowThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; FgColor, BgColor: Cardinal);
Procedure DrawShadowThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; FgColor, BgColor: TSDL_Color);
Procedure DrawCircle(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: Cardinal);
Procedure DrawCircle(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: TSDL_Color);
Procedure DrawCircleSolid(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: Cardinal);
Procedure DrawCircleSolid(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: TSDL_Color);
Procedure BiltInLeft(DstSurface, SrcSurface: PSDL_Surface);
Procedure BiltInRight(DstSurface, SrcSurface: PSDL_Surface);
Procedure BiltInUp(DstSurface, SrcSurface: PSDL_Surface);
Procedure BiltInDown(DstSurface, SrcSurface: PSDL_Surface);

Implementation

Var
    ArySin, AryCos: Array[0..360] Of Double;

Procedure InitSinCos;
Var
    Rad: Double;
    I: Integer;
Begin
    For I := 0 To 180 Do
    Begin
        Rad       := Pi * I / 360;
        ArySin[I] := Sin(Rad);
        AryCos[I] := Cos(Rad);
        ArySin[I + 180] := -ArySin[I];
        AryCos[I + 180] := AryCos[I];
    End;
End;

Procedure DrawCircle(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: Cardinal);
Var
    X1, Y1: Double;
    I: Integer;
Begin
    For I := 0 To 180 Do
    Begin
        X1 := ArySin[I] * R;
        Y1 := AryCos[I] * R;
        DrawPixel(DstSurface, Round(X0 + X1), Round(Y0 + Y1), Color);
        DrawPixel(DstSurface, Round(X0 - X1), Round(Y0 + Y1), Color);
        DrawPixel(DstSurface, Round(X0 + X1), Round(Y0 - Y1), Color);
        DrawPixel(DstSurface, Round(X0 - X1), Round(Y0 - Y1), Color);
    End;
End;

Procedure DrawCircle(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: TSDL_Color);
Begin
    DrawCircle(DstSurface, X0, Y0, R, SDL_MapRGB(DstSurface^.Format,
        Color.R, Color.G, Color.B));
End;

Procedure DrawCircleSolid(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: Cardinal; Alpha: Uint8);
Begin
    DrawCircle(DstSurface, X0, Y0, R, SDL_MapRGBA(DstSurface^.Format,
    (Color shr 16) and $ff, (Color shr 8) and $ff, Color and $ff, Alpha));
End;

Procedure DrawCircleSolid(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: Cardinal);
Var
    X1, Y1: Double;
    I: Integer;
    MyRect: TSDL_Rect;
Begin
    For I := 0 To 180 Do
    Begin
        X1       := ArySin[I] * R;
        Y1       := AryCos[I] * R;
        MyRect.X := Round(X0 - X1);
        MyRect.Y := Round(Y0 - Y1);
        MyRect.W := Round(2 * X1);
        MyRect.H := Round(2 * Y1);
        SDL_FillRect(DstSurface, @MyRect, Color);
    End;
End;

Procedure DrawCircleSolid(DstSurface: PSDL_Surface; X0, Y0, R: Integer;
    Color: TSDL_Color);
Begin
    DrawCircleSolid(DstSurface, X0, Y0, R,
        SDL_MapRGB(DstSurface^.Format, Color.R, Color.G, Color.B));
End;

Procedure DrawLine(DstSurface: PSDL_Surface; X1, Y1, X2, Y2: Integer;
    Color: Cardinal);
Var
    Dx, Dy, Sdx, Sdy, X, Y, Px, Py: Integer;
Begin
    Dx := X2 - X1;
    Dy := Y2 - Y1;
    If Dx < 0 Then 
    Sdx := -1
    Else 
    Sdx := 1;
    If Dy < 0 Then 
    Sdy := -1
    Else 
    Sdy := 1;
    Dx := Sdx * Dx + 1;
    Dy := Sdy * Dy + 1;
    X := 0;
    Y := 0;
    Px := X1;
    Py := Y1;
    If Dx >= Dy Then
    Begin
        For X := 0 To Dx - 1 Do
        Begin
            DrawPixel(DstSurface, Px, Py, Color);
            Y := Y + Dy;
            If Y >= Dx Then
            Begin
                Y  := Y - Dx;
                Py := Py + Sdy;
            End;
            Px := Px + Sdx;
        End;
    End
    Else
    Begin
        For Y := 0 To Dy - 1 Do
        Begin
            DrawPixel(DstSurface, Px, Py, Color);
            X := X + Dx;
            If X >= Dy Then
            Begin
                X := X - Dy;
                Px := Px + Sdx;
            End;
            Py := Py + Sdy;
        End;
    End;
End;

Procedure AaDrawLine(Dst: PSDL_Surface; X1, Y1, X2, Y2: Integer;
    Color: Cardinal);
Var
    Xx0, Yy0, Xx1, Yy1: Integer;
    Intshift, Erracc, Erradj: Uint32;
    Erracctmp, Wgt: Uint32;
    Dx, Dy, Tmp, Xdir, Y0p1, X0pxdir: Integer;
Begin
    If ((Dst^.Clip_rect.W = 0) and (Dst^.Clip_rect.H = 0)) Then Exit;
    Xx0 := X1;
    Yy0 := Y1;
    Xx1 := X2;
    Yy1 := Y2;
    If (Yy0 > Yy1) Then
    Begin
        Tmp := Yy0;
        Yy0 := Yy1;
        Yy1 := Tmp;
        Tmp := Xx0;
        Xx0 := Xx1;
        Xx1 := Tmp;
    End;
    Dx := Xx1 - Xx0;
    Dy := Yy1 - Yy0;
    If (Dx >= 0) Then Xdir := 1
    Else
    Begin
        Xdir := -1;
        Dx   := (-Dx);
    End;
    If (Dx = 0) or (Dy = 0) or (Dx = Dy) Then
    Begin
        DrawLine(Dst, X1, Y1, X2, Y2, Color);
        Exit;
    End;
    Erracc := 0;
    Intshift := 16;
    DrawPixel(Dst, X1, Y1, Color);
    If (Dy > Dx) Then
    Begin
        Erradj  := ((Dx shl 16) div Dy) shl 16;
        X0pxdir := Xx0 + Xdir;
        Dec(Dy);
        While (Dy <> 0) Do
        Begin
            Erracctmp := Erracc;
            Inc(Erracc, Erradj);
            If (Erracc <= Erracctmp) Then
            Begin
                Xx0 := X0pxdir;
                Inc(X0pxdir, Xdir);
            End;
            Inc(Yy0);
            Wgt := (Erracc shr Intshift) and 255;
            DrawPixel(Dst, Xx0, Yy0, Color, 255 - Wgt);
            DrawPixel(Dst, X0pxdir, Yy0, Color, Wgt);
            Dec(Dy);
        End;
    End
    Else
    Begin
        Erradj := ((Dy shl 16) div Dx) shl 16;
        Y0p1   := Yy0 + 1;
        Dec(Dx);
        While (Dx <> 0) Do
        Begin
            Erracctmp := Erracc;
            Inc(Erracc, Erradj);
            If (Erracc <= Erracctmp) Then
            Begin
                Yy0 := Y0p1;
                Inc(Y0p1);
            End;
            Inc(Xx0, Xdir);
            Wgt := (Erracc shr Intshift) and 255;
            DrawPixel(Dst, Xx0, Yy0, Color, 255 - Wgt);
            DrawPixel(Dst, Xx0, Y0p1, Color, Wgt);
            Dec(Dx);
        End;
    End;
    DrawPixel(Dst, X2, Y2, Color);
End;

Procedure DrawLine(DstSurface: PSDL_Surface; X1, Y1, X2, Y2: Integer;
    Color: TSDL_Color);
Begin
    DrawLine(DstSurface, X1, Y1, X2, Y2, SDL_MapRGB(DstSurface^.Format,
        Color.R, Color.G, Color.B));
End;

Procedure AaDrawThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; Color: Cardinal);
Var
    Xx0, Yy0, Xx1, Yy1: Integer;
    Intshift, Erracc, Erradj: Uint32;
    Erracctmp, Wgt: Uint32;
    Dx, Dy, Tmp, Xdir, Y0p1, X0pxdir: Integer;
    Circle, Tmpsf: PSDL_Surface;
    MyRect: TSDL_Rect;
Begin
    Circle := SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Width, 32, 0, 0, 0, 0);
    SDL_FillRect(Circle, Nil, $ffffff - Color);
    SDL_SetColorKey(Circle, SDL_SRCCOLORKEY, $ffffff - Color);
    DrawCircleSolid(Circle, Round(Width / 2), Round(Width / 2), Round(Width / 2), Color);
    If ((DstSurface^.Clip_rect.W = 0) and (DstSurface^.Clip_rect.H = 0)) Then Exit;
    Xx0 := X1;
    Yy0 := Y1;
    Xx1 := X2;
    Yy1 := Y2;
    If (Yy0 > Yy1) Then
    Begin
        Tmp := Yy0;
        Yy0 := Yy1;
        Yy1 := Tmp;
        Tmp := Xx0;
        Xx0 := Xx1;
        Xx1 := Tmp;
    End;
    Dx := Xx1 - Xx0;
    Dy := Yy1 - Yy0;
    If (Dx >= 0) Then Xdir := 1
    Else
    Begin
        Xdir := -1;
        Dx   := (-Dx);
    End;
    If (Dx = 0) or (Dy = 0) or (Dx = Dy) Then
    Begin
        DrawThickLine(DstSurface, X1, Y1, X2, Y2, Width, Color);
        SDL_FreeSurface(Circle);
        Exit;
    End;
    Erracc := 0;
    Intshift := 16;
    If (Dy > Dx) Then
    Begin
        Erradj  := ((Dx shl 16) div Dy) shl 16;
        X0pxdir := Xx0 + Xdir;
        Dec(Dy);
        While (Dy <> 0) Do
        Begin
            Erracctmp := Erracc;
            Inc(Erracc, Erradj);
            If (Erracc <= Erracctmp) Then
            Begin
                Xx0 := X0pxdir;
                Inc(X0pxdir, Xdir);
            End;
            Inc(Yy0);
            Wgt := (Erracc shr Intshift) and 255;
            MyRect.X := Round(Xx0 - Width / 2);
            MyRect.Y := Round(Yy0 - Width / 2);
            MyRect.W := Width;
            MyRect.H := Width;
            Tmpsf := SDL_DisplayFormat(Circle);
            SDL_SetAlpha(Tmpsf, Color, 255 - Wgt);
            SDL_BlitSurface(Tmpsf, Nil, DstSurface, @MyRect);
            SDL_FreeSurface(Tmpsf);
            MyRect.X := Round(X0pxdir - Width / 2);
            MyRect.Y := Round(Yy0 - Width / 2);
            MyRect.W := Width;
            MyRect.H := Width;
            Tmpsf := SDL_DisplayFormat(Circle);
            SDL_SetAlpha(Tmpsf, Color, Wgt);
            SDL_BlitSurface(Tmpsf, Nil, DstSurface, @MyRect);
            SDL_FreeSurface(Tmpsf);
            Dec(Dy);
        End;
    End
    Else
    Begin
        Erradj := ((Dy shl 16) div Dx) shl 16;
        Y0p1   := Yy0 + 1;
        Dec(Dx);
        While (Dx <> 0) Do
        Begin
            Erracctmp := Erracc;
            Inc(Erracc, Erradj);
            If (Erracc <= Erracctmp) Then
            Begin
                Yy0 := Y0p1;
                Inc(Y0p1);
            End;
            Inc(Xx0, Xdir);
            Wgt := (Erracc shr Intshift) and 255;
            MyRect.X := Round(Xx0 - Width / 2);
            MyRect.Y := Round(Yy0 - Width / 2);
            MyRect.W := Width;
            MyRect.H := Width;
            Tmpsf := SDL_DisplayFormat(Circle);
            SDL_SetAlpha(Tmpsf, Color, 255 - Wgt);
            SDL_BlitSurface(Tmpsf, Nil, DstSurface, @MyRect);
            SDL_FreeSurface(Tmpsf);
            MyRect.X := Round(Xx0 - Width / 2);
            MyRect.Y := Round(Y0p1 - Width / 2);
            MyRect.W := Width;
            MyRect.H := Width;
            Tmpsf := SDL_DisplayFormat(Circle);
            SDL_SetAlpha(Tmpsf, Color, Wgt);
            SDL_BlitSurface(Tmpsf, Nil, DstSurface, @MyRect);
            SDL_FreeSurface(Tmpsf);
            Dec(Dx);
        End;
    End;
    MyRect.X := Round(X1 - Width / 2);
    MyRect.Y := Round(Y1 - Width / 2);
    MyRect.W := Width;
    MyRect.H := Width;
    SDL_BlitSurface(Circle, Nil, DstSurface, @MyRect);
    MyRect.X := Round(X2 - Width / 2);
    MyRect.Y := Round(Y2 - Width / 2);
    MyRect.W := Width;
    MyRect.H := Width;
    SDL_BlitSurface(Circle, Nil, DstSurface, @MyRect);
    SDL_FreeSurface(Circle);
End;

Procedure AaDrawThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; Color: TSDL_Color);
Begin
    AaDrawThickLine(DstSurface, X1, Y1,
        X2, Y2, Width, SDL_MapRGB(DstSurface^.Format, Color.R, Color.G, Color.B));
End;

Procedure DrawThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; Color: Cardinal);
Var
    Dx, Dy, Sdx, Sdy, X, Y, Px, Py: Integer;
    Circle: PSDL_Surface;
    MyRect: TSDL_Rect;
Begin
    Circle := SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Width, 32, 0, 0, 0, 0);
    SDL_FillRect(Circle, Nil, $ffffff - Color);
    SDL_SetColorKey(Circle, SDL_SRCCOLORKEY, $ffffff - Color);
    DrawCircleSolid(Circle, Round(Width / 2), Round(Width / 2), Round(Width / 2), Color);
    Dx := X2 - X1;
    Dy := Y2 - Y1;
    If Dx < 0 Then 
    Sdx := -1
    Else 
    Sdx := 1;
    If Dy < 0 Then 
    Sdy := -1
    Else 
    Sdy := 1;
    Dx := Sdx * Dx + 1;
    Dy := Sdy * Dy + 1;
    X := 0;
    Y := 0;
    Px := X1;
    Py := Y1;
    If Dx >= Dy Then
    Begin
        For X := 0 To Dx - 1 Do
        Begin
            MyRect.X := Round(Px - Width / 2);
            MyRect.Y := Round(Py - Width / 2);
            MyRect.W := Width;
            MyRect.H := Width;
            SDL_BlitSurface(Circle, Nil, DstSurface, @MyRect);
            Y := Y + Dy;
            If Y >= Dx Then
            Begin
                Y := Y - Dx;
                Py := Py + Sdy;
            End;
            Px := Px + Sdx;
        End;
    End
    Else
    Begin
        For Y := 0 To Dy - 1 Do
        Begin
            MyRect.X := Round(Px - Width / 2);
            MyRect.Y := Round(Py - Width / 2);
            MyRect.W := Width;
            MyRect.H := Width;
            SDL_BlitSurface(Circle, Nil, DstSurface, @MyRect);
            X := X + Dx;
            If X >= Dy Then
            Begin
                X  := X - Dy;
                Px := Px + Sdx;
            End;
            Py := Py + Sdy;
        End;
    End;
    SDL_FreeSurface(Circle);
End;

Procedure DrawThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; Color: TSDL_Color);
Begin
    DrawThickLine(DstSurface, X1, Y1, X2, Y2, Width,
        SDL_MapRGB(DstSurface^.Format, Color.R, Color.G, Color.B));
End;

Procedure AaDrawShadowThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; FgColor, BgColor: Cardinal);
Begin
    AaDrawThickLine(DstSurface, X1, Y1, X2, Y2, Width, BgColor);
    AaDrawThickLine(DstSurface, X1, Y1, X2, Y2, Width div 2, FgColor);
End;

Procedure DrawShadowThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; FgColor, BgColor: Cardinal);
Begin
    DrawThickLine(DstSurface, X1, Y1, X2, Y2, Width, BgColor);
    DrawThickLine(DstSurface, X1, Y1, X2, Y2, Width div 2, FgColor);
End;

Procedure AaDrawShadowThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; FgColor, BgColor: TSDL_Color);
Begin
    AaDrawShadowThickLine(DstSurface, X1, Y1, X2, Y2, Width,
        SDL_MapRGB(DstSurface^.Format, FgColor.R, FgColor.G, FgColor.B),
        SDL_MapRGB(DstSurface^.Format, BgColor.R, BgColor.G, BgColor.B));
End;

Procedure DrawShadowThickLine(DstSurface: PSDL_Surface;
    X1, Y1, X2, Y2, Width: Integer; FgColor, BgColor: TSDL_Color);
Begin
    DrawShadowThickLine(DstSurface, X1, Y1, X2, Y2, Width,
        SDL_MapRGB(DstSurface^.Format, FgColor.R, FgColor.G, FgColor.B),
        SDL_MapRGB(DstSurface^.Format, BgColor.R, BgColor.G, BgColor.B));
End;

Procedure BiltInLeft(DstSurface, SrcSurface: PSDL_Surface);
Var
    Width, Height: Integer;
    St, Ed: DWORD;
    SrcRect: SDL_Rect;
Begin
    Height := DstSurface^.H;
    Width := DstSurface^.W;
    SrcRect.X := Width;
    SrcRect.Y := 0;
    SrcRect.W := 0;
    SrcRect.H := Height;
    While SrcRect.X - 25 >= 0 Do
    Begin
        St := GetTickCount();
        Dec(SrcRect.X, 25);
        Inc(SrcRect.W, 25);
        SDL_BlitSurface(SrcSurface, Nil, DstSurface, @SrcRect);
        SDL_UpdateRect(DstSurface, SrcRect.X, 0, SrcRect.W, Height);
        Ed := GetTickCount();
        If Ed - St < 33 Then Sleep(33 - Ed + St);
    End;
End;

Procedure BiltInRight(DstSurface, SrcSurface: PSDL_Surface);
Var
    I, Width, Height: Integer;
    SrcRect: SDL_Rect;
Begin
    Height := DstSurface^.H;
    Width := DstSurface^.W;
    I := 0;
    SrcRect.H := Height;
    SrcRect.Y := 0;
    SrcRect.W := 0;
    SrcRect.X := Width;
    While I <= Width - 25 Do
    Begin
        Inc(I, 25);
        Dec(SrcRect.X, 25);
        SDL_BlitSurface(SrcSurface, @SrcRect, DstSurface, Nil);
        SDL_UpdateRect(DstSurface, 0, 0, I, Height);
    End;
End;

Procedure BiltInUp(DstSurface, SrcSurface: PSDL_Surface);
Var
    I, Width, Height: Integer;
    SrcRect: SDL_Rect;
Begin
    Height := DstSurface^.H;
    Width := DstSurface^.W;
    I := 0;
    SrcRect.X := 0;
    SrcRect.Y := Height;
    SrcRect.W := Width;
    SrcRect.H := 0;
    While I <= Height - 25 Do
    Begin
        Inc(I, 25);
        Dec(SrcRect.Y, 25);
        Inc(SrcRect.H, 25);
        SDL_BlitSurface(SrcSurface, Nil, DstSurface, @SrcRect);
        SDL_UpdateRect(DstSurface, 0, SrcRect.Y, Width, I);
    End;
End;

Procedure BiltInDown(DstSurface, SrcSurface: PSDL_Surface);
Var
    I, Width, Height: Integer;
    SrcRect: SDL_Rect;
Begin
    Height := DstSurface^.H;
    Width := DstSurface^.W;
    I := 0;
    SrcRect.X := 0;
    SrcRect.Y := Height;
    SrcRect.W := Width;
    SrcRect.H := 0;
    While I <= Height - 25 Do
    Begin
        Inc(I, 25);
        Dec(SrcRect.Y, 25);
        Inc(SrcRect.H, 25);
        SDL_BlitSurface(SrcSurface, @SrcRect, DstSurface, Nil);
        SDL_UpdateRect(DstSurface, 0, 0, Width, I);
    End;
End;

Procedure RotateSurfaceRad(DstSurface, SrcSurface: PSDL_Surface;
    SrcRect: PSDL_Rect; DestX, DestY, OffsetX, OffsetY: Integer; Angle: Single);
Begin
    RotateSurfaceDeg(DstSurface, SrcSurface, SrcRect, DestX, DestY,
        OffsetX, OffsetY, Round(Angle * 180 / Pi + 0.5));
End;

Procedure RotateSurfaceDeg(DstSurface, SrcSurface: PSDL_Surface;
    SrcRect: PSDL_Rect; DestX, DestY, OffsetX, OffsetY: Integer; Angle: Integer);
Var
    ASin, ACos: Single;
    MX, MY, DX, DY, NX, NY, SX, SY, OX, OY, Width, Height, TX, TY,
    RX, RY, ROX, ROY: Integer;
    Colour, TempTransparentColour: UInt32;
    MAXX, MAXY: Integer;
Begin
    TempTransparentColour := SrcSurface^.Format^.Colorkey;
    Maxx := DstSurface^.W;
    Maxy := DstSurface^.H;
    ACos := AryCos[Angle mod 360];
    ASin := ArySin[Angle mod 360];
    Width := Round(Abs(Srcrect^.H * Acos) + Abs(Srcrect^.W * Asin));
    Height := Round(Abs(Srcrect^.H * Asin) + Abs(Srcrect^.W * Acos));
    OX := Width div 2;
    OY := Height div 2;;
    MX := (SrcRect^.X + (SrcRect^.X + SrcRect^.W)) div 2;
    MY := (SrcRect^.Y + (SrcRect^.Y + SrcRect^.H)) div 2;
    ROX := (-(SrcRect^.W div 2)) + Offsetx;
    ROY := (-(SrcRect^.H div 2)) + OffsetY;
    Tx := Ox + Round(ROX * ASin - ROY * ACos);
    Ty := Oy + Round(ROY * ASin + ROX * ACos);
    SX := 0;
    For DX := DestX - TX To DestX - TX + (Width) Do
    Begin
        Inc(SX);
        SY := 0;
        For DY := DestY - TY To DestY - TY + (Height) Do
        Begin
            RX := SX - OX;
            RY := SY - OY;
            NX := Round(Mx + RX * ASin + RY * ACos);
            NY := Round(My + RY * ASin - RX * ACos);
            If ((DX > 0) and (DX < MAXX)) and ((DY > 0) and (DY < MAXY)) Then
            Begin
                If (NX >= SrcRect^.X) and (NX <= SrcRect^.X + SrcRect^.W) Then
                Begin
                    If (NY >= SrcRect^.Y) and (NY <= SrcRect^.Y + SrcRect^.H) Then
                    Begin
                        Colour := PixelColor(SrcSurface, NX, NY);
                        If Colour <> TempTransparentColour Then
                        Begin
                            DrawPixel(DstSurface, DX, DY, Colour);
                        End;
                    End;
                End;
            End;
            Inc(SY);
        End;
    End;
End;

Procedure DrawPixel(DstSurface: Psdl_surface; X, Y: Integer; R, G, B, Alpha: Uint8);
Var
    Color: UINT32;
Begin
    Color := Sdl_maprgba(DstSurface^.Format, R, G, B, Alpha);
    DrawPixel(DstSurface, X, Y, Color);
End;

Procedure DrawPixel(DstSurface: Psdl_surface; X, Y: Integer; R, G, B: Uint8);
Var
    Color: UINT32;
Begin
    Color := Sdl_maprgb(DstSurface^.Format, R, G, B);
    DrawPixel(DstSurface, X, Y, Color);
End;

Procedure DrawPixel(DstSurface: Psdl_surface; X, Y: Integer; Color: Uint32);
Var
    Bufp: PUINT8;
Begin
    While SDL_LockSurface(DstSurface) <> 0 Do;
    Bufp := DstSurface^.Pixels + Y * DstSurface^.Pitch + X * DstSurface^.Format^.BytesPerPixel;
    If (DstSurface^.Format^.Bytesperpixel = 1) Then Bufp^ := Color;
    If (DstSurface^.Format^.Bytesperpixel = 2) Then PUINT16(Bufp)^ := Color;
    If (DstSurface^.Format^.Bytesperpixel = 3) Then
    Begin
        If (SDL_BYTEORDER = SDL_BIG_ENDIAN) Then
        Begin
            Bufp^ := (Color shr 16) and $ff;
            (Bufp + 1)^ := (Color shr 8) and $ff;
            (Bufp + 2)^ := Color and $ff;
        End
        Else
        Begin
            Bufp^ := Color and $ff;
            (Bufp + 1)^ := (Color shr 8) and $ff;
            (Bufp + 2)^ := (Color shr 16) and $ff;
        End;
    End;
    If (DstSurface^.Format^.Bytesperpixel = 4) Then PUINT32(Bufp)^ := Color;
    SDL_UnLockSurface(DstSurface);
End;

Procedure DrawPixel(DstSurface: Psdl_surface; X, Y: Integer;
    Color: Uint32; Alpha: Uint8);
Begin
    DrawPixel(DstSurface, X, Y, (Color shr 16) and $ff,
    (Color shr 8) and $ff, Color and $ff, Alpha);
End;

Function PixelColor(SrcSurface: Psdl_surface; X, Y: Integer): UINT32;
Var
    Bufp: PUINT8;
    Buf32: UINT32;
Begin
    Buf32 := 0;
    Bufp := SrcSurface^.Pixels + Y * SrcSurface^.Pitch + X *
        SrcSurface^.Format^.BytesPerPixel;
    If (SrcSurface^.Format^.Bytesperpixel = 1) Then Exit(Bufp^);
    If (SrcSurface^.Format^.Bytesperpixel = 2) Then Exit(PUINT16(Bufp)^);
    If (SrcSurface^.Format^.Bytesperpixel = 3) Then
    Begin
        If (SDL_BYTEORDER = SDL_BIG_ENDIAN) Then
        Begin
            Buf32 := (Bufp^ shl 16) + ((Bufp + 1)^ shl 8) + (Bufp + 2)^;
            Exit(Buf32);
        End
        Else
        Begin
            Buf32 := Bufp^ +((Bufp + 1)^ shl 8) + ((Bufp + 2)^ shl 16);
            Exit(Buf32);
        End;
    End;
    If (SrcSurface^.Format^.Bytesperpixel = 4) Then Exit(PUINT32(Bufp)^);
End;

Function CloseColor(Fg_color, Bg_color, Color: UINT32): Boolean;
Var
    Fg, Bg, Chk: TSDL_Color;
    Dis_fg, Dis_bg: ValReal;
Begin
    Fg.R := (Fg_color and $ff0000) shr 4;
    Fg.G := (Fg_color and $00ff00) shr 2;
    Fg.B := (Fg_color and $0000ff);
    Bg.R := (Bg_color and $ff0000) shr 4;
    Bg.G := (Bg_color and $00ff00) shr 2;
    Bg.B := (Bg_color and $0000ff);
    Chk.R := (Color and $ff0000) shr 4;
    Chk.G := (Color and $00ff00) shr 2;
    Chk.B := (Color and $0000ff);
    Dis_fg := Sqrt(Sqr(Chk.R - Fg.R) + Sqr(Chk.G - Fg.B) + Sqr(Chk.B - Fg.B));
    Dis_bg := Sqrt(Sqr(Chk.R - Bg.R) + Sqr(Chk.G - Bg.B) + Sqr(Chk.B - Bg.B));
    If Abs(Color - Fg_color) > Abs(Color - Bg_color) Then Exit(True);
    If Dis_fg > Dis_bg Then Exit(True);
    Exit(False);
End;

Function LoadImage(ImageFile: String): PSDL_Surface;
Var
    Temp, Tmp: PSDL_Surface;
Begin
    Temp := IMG_Load(PChar(ImageFile));
    If Temp = Nil Then Exit(Nil);
    Tmp := SDL_DisplayFormat(Temp);
    SDL_FreeSurface(Temp);
    Exit(Tmp);
End;

Function LoadImageAlpha(ImageFile: String): PSDL_Surface;
Var
    Temp, Tmp: PSDL_Surface;
Begin
    Temp := IMG_Load(PChar(ImageFile));
    If Temp = Nil Then Exit(Nil);
    Tmp := SDL_DisplayFormatAlpha(Temp);
    SDL_FreeSurface(Temp);
    Exit(Tmp);
End;

Function CreateColorSurface(Width, Height: Integer;
    Color: TSDL_Color): PSDL_Surface;
Var
    Tmp, Temp: PSDL_Surface;
Begin
    Temp := SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Height, 32, 0, 0, 0, 0);
    If Temp = Nil Then Exit(Nil);
    Tmp := SDL_DisplayFormat(Temp);
    SDL_FreeSurface(Temp);
    If Tmp = Nil Then Exit(Nil);
    SDL_FillRect(Tmp, Nil, SDL_MapRGB(Tmp^.Format, Color.R, Color.G, Color.B));
    Exit(Tmp);
End;

Procedure TransparentColor(PaintBoard: PSDL_Surface; Color: TSDL_Color);
Begin
    SDL_SetColorKey(PaintBoard, SDL_SRCCOLORKEY,
        SDL_MapRGB(PaintBoard^.Format, Color.R, Color.G, Color.B));
End;

Procedure TransparentColor(PaintBoard: PSDL_Surface; Color: UINT32);
Begin
    SDL_SetColorKey(PaintBoard, SDL_SRCCOLORKEY, Color);
End;

Procedure AlphaSourceSurface(PaintBoard: PSDL_Surface; Alpha: Uint8);
Begin
    SDL_SetAlpha(PaintBoard, SDL_SRCALPHA, Alpha);
End;

Procedure BlitSurface(SrcSurface: PSDL_Surface; SrcRect: PSDL_Rect;
    DesSurface: PSDL_Surface; DesRect: PSDL_Rect);
Begin
    SDL_BlitSurface(SrcSurface, SrcRect, DesSurface, DesRect);
End;

Procedure AlphaBlitSurface(SrcSurface: PSDL_Surface; SrcRect: PSDL_Rect;
    DesSurface: PSDL_Surface; DesRect: PSDL_Rect; Alpha: Uint8);
Begin
    SDL_SetAlpha(SrcSurface, SDL_SRCALPHA, Alpha);
    SDL_BlitSurface(SrcSurface, SrcRect, DesSurface, DesRect);
End;

Procedure FreeSurface(Var ImageSurface: PSDL_Surface);
Begin
    SDL_FreeSurface(ImageSurface);
    ImageSurface := Nil;
End;

Function OpenTTFFont(Font_file: String; Font_size: Integer): PTTF_FONT;
Begin
    If TTF_Init() = -1 Then Exit(Nil);
    Exit(Ttf_OpenFont(PChar(Font_file), Font_size));
End;

Procedure CloseTTFFont(Var Font: PTTF_FONT);
Begin
    If Font <> Nil Then TTF_CloseFont(Font);
    Ttf_quit();
End;

Function BackupSurface(PaintBoard: PSDL_Surface;
    BackupRect: TSDL_Rect): PSDL_Surface;
Var
    Temp: PSDL_Surface;
Begin
    If BackupRect.W + BackupRect.X > PaintBoard^.W Then
    BackupRect.W := PaintBoard^.W - BackupRect.X;
    If BackupRect.H + BackupRect.Y > PaintBoard^.H Then
    BackupRect.W := PaintBoard^.H - BackupRect.Y;
    If (BackupRect.W <= 0) or (BackupRect.H <= 0) Then Exit(Nil);
    Temp := SDL_CreateRGBSurface(SDL_SWSURFACE, BackupRect.W, BackupRect.H, 32, 0, 0, 0, 0);
    If Temp = Nil Then Exit(Nil);
    Result := SDL_DisplayFormat(Temp);
    SDL_FreeSurface(Temp);
    SDL_BlitSurface(PaintBoard, @BackupRect, Result, Nil);
End;

Procedure RestoreSurface(PaintBoard: PSDL_Surface;
    BackupSurface: PSDL_Surface; BackupRect: TSDL_Rect);
Begin
    SDL_BlitSurface(BackupSurface, Nil, PaintBoard, @BackupRect);
    SDL_UpdateRect(PaintBoard, BackupRect.X, BackupRect.Y, BackupRect.W, BackupRect.H);
End;

End.
